import { Plank } from '@/components';
import { EditorCanvasElement } from '@/components/Editor/EditorCanvasElement';
import { GizmoViewcube } from '@/components/GizmoViewcube';
import { GizmoViewport } from '@/components/GizmoViewport';
import { PlankPropsValidate } from '@/components/Plank/validate/components/PlankPropsValidate';
import { axisColorConfig, canvasBgColor } from '@/config/stage-canvas-config';
import { EGrooveGeometryType, Groove, IPlank } from '@/types';
import {
  GizmoHelper,
  OrbitControls,
  OrthographicCamera,
  PerspectiveCamera,
} from '@react-three/drei';
import { Canvas, useThree } from '@react-three/fiber';
import { useMount } from 'ahooks';
import { Alert, message } from 'antd';
import { clone } from 'lodash-es';
import { ComponentRef, useMemo, useRef } from 'react';
import { AxesHelper, Color } from 'three';
import { useModel } from 'umi';

function StageCanvasChildren() {
  const {
    plank,
    setPlank,
    holeId,
    setHoleId,
    hoveredHoleId,
    setHoveredHoleId,
    grooveId,
    setGrooveId,
    hoveredGrooveId,
    setHoveredGrooveId,
    hoveredPlank,
    setHoveredPlank,
    basis,
  } = useModel('bom');
  const {
    isShowEdge,
    isShowProfileTipPoint,
    showBasis,
    highlightProfilePoint,
  } = useModel('StageCanvas');
  const hole = plank?.holes.find((hole) => hole.holeId === holeId);
  const hoveredHole = plank?.holes.find(
    (hole) => hole.holeId === hoveredHoleId,
  );
  const grooveFind = (grooveId: string) =>
    plank?.grooves.find((groove) => groove.grooveId === grooveId);
  function grooveEventInterceptor(grooveId?: string) {
    if (!grooveId) return true;
    const groove = grooveFind(grooveId)!;
    grooveFind(groove.grooveId);
    if (!isGrooveEditable(groove)) {
      onGrooveUnEditable();
      return false;
    }
    return true;
  }
  const groove = plank?.grooves.find((groove) => groove.grooveId === grooveId);
  const hoveredGroove = plank?.grooves.find(
    (groove) => groove.grooveId === hoveredGrooveId,
  );

  const orbitControlsRef = useRef<ComponentRef<typeof OrbitControls>>(null);
  const get = useThree(({ get }) => get);
  useMount(() => {
    const eventListenerTarget: HTMLElement = get().events.connected;
    const createSyntheticWheelEvent = (deltaY: number) =>
      new WheelEvent('wheel', {
        deltaY: deltaY,
        deltaMode: 0,
      });
    const syntheticWheeldeltaYAddEvent = createSyntheticWheelEvent(100);
    const syntheticWheeldeltaYSubEvent = createSyntheticWheelEvent(-100);
    eventListenerTarget.addEventListener('keydown', (e) => {
      const { code } = e;
      switch (code) {
        case 'KeyW':
          eventListenerTarget.dispatchEvent(syntheticWheeldeltaYAddEvent);
          break;
        case 'KeyS':
          eventListenerTarget.dispatchEvent(syntheticWheeldeltaYSubEvent);
          break;

        default:
          break;
      }
    });
    setTimeout(() => {
      const orbitControls = orbitControlsRef.current!;
      orbitControls.listenToKeyEvents(eventListenerTarget);
    }, 1000);
  });

  const axesHelperRef = useRef<AxesHelper>(null);
  useMount(() => {
    const axesHelper = axesHelperRef.current;
    axesHelper?.setColors(
      new Color(axisColorConfig.x),
      new Color(axisColorConfig.y),
      new Color(axisColorConfig.z),
    );
  });

  return (
    <>
      <PerspectiveCamera
        far={140000}
        near={10}
        makeDefault
        up={[0, 0, 1]}
        position={[1400, -600, 500]}
        rotation={[0, 0, 0]}
      />
      <OrbitControls
        ref={orbitControlsRef}
        keyEvents={false}
        keys={{ LEFT: 'KeyA', RIGHT: 'KeyD', UP: 'KeyQ', BOTTOM: 'KeyE' }}
        makeDefault
        enableDamping={false}
      />
      {/* <Plane /> */}
      <axesHelper
        ref={axesHelperRef}
        position={[
          -(plank?.finishedWidth ?? 0) / 2,
          -(plank?.finishedHeight ?? 0) / 2,
          -(plank?.thickness ?? 0) / 2,
        ]}
        args={[1000]}
      />
      <ambientLight intensity={0.8} />
      <pointLight intensity={0.2} position={[600, 200, 1400]} />
      <GizmoHelper alignment="top-right" margin={[100, 100]}>
        <group position={[24, 24, 24]}>
          <GizmoViewcube
            scale={40}
            faces={['右', '左', '后', '前', '顶', '底']}
          />
        </group>
        <GizmoViewport scale={48} />
      </GizmoHelper>
      {plank && (
        <Plank
          profile={plank.finishedProfile}
          inners={plank.inners}
          width={plank.finishedWidth}
          height={plank.finishedHeight}
          holes={plank.holes}
          thickness={plank.thickness}
          grooves={plank.grooves}
          hightLight={{
            holes: holeId ? [holeId] : [],
            grooves: grooveId ? [grooveId] : [],
          }}
          edgeBanding={isShowEdge ? plank.edgeBanding : []}
          // @ts-ignore
          textureDirection={plank.textureDirection}
          onHoleClick={(holeId) => {
            const hole = plank.holes.find((hole) => hole.holeId === holeId);
            if (hole) {
            }
            // log('holeId', holeId,);
            setHoleId(holeId);
          }}
          onHoleHover={(holeId) => {
            setHoveredHoleId(holeId);
          }}
          onGrooveClick={(grooveId) => {
            grooveEventInterceptor(grooveId) && setGrooveId(grooveId);
          }}
          onGrooveHover={(grooveId) => {
            grooveEventInterceptor(grooveId) && setHoveredGrooveId(grooveId);
          }}
          onPlankHover={(hovered) => {
            // console.log('hovered', hovered);
            setHoveredPlank(hovered);
          }}
        />
      )}
      {plank && (
        <EditorCanvasElement
          plank={{
            width: plank.finishedWidth,
            height: plank.finishedHeight,
            thickness: plank.thickness,
            hole,
            hoveredHole,
            groove,
            hoveredGroove,
            hoveredPlank,
            profile: isShowProfileTipPoint
              ? plank.finishedProfile
              : { curves: [], points: [] },
          }}
          basis={basis}
          showBasis={showBasis}
          highlightProfilePoint={highlightProfilePoint}
          onChangeHole={() => {
            setPlank(clone(plank));
          }}
          onChangeGroove={() => {
            setPlank(clone(plank));
          }}
          onChangeProfile={() => {
            // console.log(plank.finishedProfile.points);
            setPlank(clone(plank));
          }}
          onStopEditHole={() => {
            setHoleId('');
          }}
          onStopEditGroove={() => {
            // console.log('stopEditGroove');
            setGrooveId('');
          }}
        />
      )}
    </>
  );
}

function isGrooveEditable(groove: Groove) {
  const { geometryType } = groove;
  if (!geometryType) return;
  return [
    EGrooveGeometryType.SQUARE,
    EGrooveGeometryType.ROUND_CORNER,
  ].includes(geometryType);
}
function onGrooveUnEditable() {
  message.warning('该对象不支持选中编辑');
}

function getPlankProps({
  plank,
  holeId,
  grooveId,
}: {
  plank: IPlank;
  holeId?: string;
  grooveId?: string;
}) {
  const profile = plank.finishedProfile;
  const width = plank.finishedWidth;
  const height = plank.finishedHeight;
  const holes = plank.holes;
  const thickness = plank.thickness;
  const grooves = plank.grooves;
  const hightLight = {
    holes: holeId ? [holeId] : [],
    grooves: grooveId ? [grooveId] : [],
  };

  return {
    ...plank,
    profile,
    width,
    height,
    holes,
    thickness,
    grooves,
    hightLight,
  };
}

function StageCanvasWithValidate() {
  const { plank, holeId, grooveId } = useModel('bom');

  const plankProps = useMemo(() => {
    return plank && getPlankProps({ plank, holeId, grooveId });
  }, [plank]);
  return (
    <PlankPropsValidate plankProps={plankProps}>
      <Canvas
        frameloop="always"
        flat
        style={{ backgroundColor: canvasBgColor }}
        tabIndex={-1}
      >
        <StageCanvasChildren />
      </Canvas>
    </PlankPropsValidate>
  );
}

export { StageCanvasWithValidate as StageCanvas };
